package com.hzgj.bcl.redis;

import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.util.Hashing;
import redis.clients.util.Pool;

import java.util.List;
import java.util.regex.Pattern;

/**
 * Created by warning5 on 17-6-6.
 */
public class ShardedXJedisPool extends Pool<ShardedXJedis> {
    public ShardedXJedisPool(final GenericObjectPoolConfig poolConfig, List<JedisShardInfo> shards) {
        this(poolConfig, shards, Hashing.MURMUR_HASH);
    }

    public ShardedXJedisPool(final GenericObjectPoolConfig poolConfig, List<JedisShardInfo> shards,
                            Hashing algo) {
        this(poolConfig, shards, algo, null);
    }

    public ShardedXJedisPool(final GenericObjectPoolConfig poolConfig, List<JedisShardInfo> shards,
                            Pattern keyTagPattern) {
        this(poolConfig, shards, Hashing.MURMUR_HASH, keyTagPattern);
    }

    public ShardedXJedisPool(final GenericObjectPoolConfig poolConfig, List<JedisShardInfo> shards,
                            Hashing algo, Pattern keyTagPattern) {
        super(poolConfig, new ShardedJedisFactory(shards, algo, keyTagPattern));
    }

    @Override
    public ShardedXJedis getResource() {
        ShardedXJedis jedis = super.getResource();
        jedis.setDataSource(this);
        return jedis;
    }

    /**
     * PoolableObjectFactory custom impl.
     */
    private static class ShardedJedisFactory implements PooledObjectFactory<ShardedXJedis> {
        private List<JedisShardInfo> shards;
        private Hashing algo;
        private Pattern keyTagPattern;

        public ShardedJedisFactory(List<JedisShardInfo> shards, Hashing algo, Pattern keyTagPattern) {
            this.shards = shards;
            this.algo = algo;
            this.keyTagPattern = keyTagPattern;
        }

        @Override
        public PooledObject<ShardedXJedis> makeObject() throws Exception {
            ShardedXJedis jedis = new ShardedXJedis(shards, algo, keyTagPattern);
            return new DefaultPooledObject<ShardedXJedis>(jedis);
        }

        @Override
        public void destroyObject(PooledObject<ShardedXJedis> pooledShardedJedis) throws Exception {
            final ShardedXJedis shardedXJedis = pooledShardedJedis.getObject();
            for (Jedis jedis : shardedXJedis.getAllShards()) {
                try {
                    try {
                        jedis.quit();
                    } catch (Exception e) {

                    }
                    jedis.disconnect();
                } catch (Exception e) {

                }
            }
        }

        @Override
        public boolean validateObject(PooledObject<ShardedXJedis> pooledShardedJedis) {
            try {
                ShardedXJedis jedis = pooledShardedJedis.getObject();
                for (Jedis shard : jedis.getAllShards()) {
                    if (!shard.ping().equals("PONG")) {
                        return false;
                    }
                }
                return true;
            } catch (Exception ex) {
                return false;
            }
        }

        @Override
        public void activateObject(PooledObject<ShardedXJedis> p) throws Exception {

        }

        @Override
        public void passivateObject(PooledObject<ShardedXJedis> p) throws Exception {

        }
    }
}
